﻿using DevelopTool.Common;
using DevelopTool.Forms.BaseForms;
using DevelopTool.Forms.CommonControls;
using DevelopTool.Model;
using DevelopTool.Model.CommonModels;
using DevelopTool.Model.Enums;
using Sunny.UI;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DevelopTool.Forms.FolderToolForms
{
    /// <summary>
    /// 查看目录大小
    /// </summary>
    public partial class FolderSizeForm : BaseUIPage
    {
        /// <summary>
        /// 目录路径
        /// </summary>
        public string FolderPath { get; set; }


        private DataDisplayControl dataDisplayControl;

        /// <summary>
        /// 结果
        /// </summary>
        private DataTable resultTable;

        /// <summary>
        /// 最后一次选择的节点
        /// </summary>
        private ManageMenu lastSelectedManageMenu;

        /// <summary>
        /// 图标缓存字典
        /// </summary>
        private Dictionary<string,Icon> IconCache = new Dictionary<string,Icon>();

        private CancellationTokenSource cts;

        /// <summary>
        /// 任务队列集合，用于统计目录大小和文件数量
        /// </summary>
        private ConcurrentBag<string> bags = new ConcurrentBag<string>();


        private long folderSize = 0;
        private int fileCount = 0;
        private int folderCount = 0;

        /// <summary>
        /// DataGridView列信息集合
        /// </summary>
        private readonly List<DataGridColumn> dataGridColumns = new List<DataGridColumn>()
              {
                { new DataGridColumn("Icon"){ColumnText="图标",Width=-1}},
                { new DataGridColumn("Name"){ColumnText="名称",Width=0,ColumnType=ColumnType.DefaultFilter}},
                { new DataGridColumn("SizeFormat"){ColumnText="占用大小",Width=100}},
                { new DataGridColumn("FileCount"){ColumnText="文件数量",Width=-1}},
                { new DataGridColumn("FolderCount"){ColumnText="目录数量",Width=-1}},
                { new DataGridColumn("Size"){ColumnText="字节大小",Width=100}},
                { new DataGridColumn("Path"){ColumnText="路径",Width=-1}},
                { new DataGridColumn("Type"){ColumnText="类型",Width=-1,ColumnType=ColumnType.Hide}},
              };

        public FolderSizeForm()
        {
            InitializeComponent();
        }

        private void FolderSizeForm_Load(object sender,EventArgs e)
        {
            this.Disposed += this.FolderSizeForm_Disposed;

            //数据展示控件
            dataDisplayControl = new DataDisplayControl();
            dataDisplayControl.TitleText = "目录/文件列表";
            dataDisplayControl.ShowReloadToolStripItem = false;
            dataDisplayControl.ShowTopSearhTextBox = false;
            dataDisplayControl.DataGridView.Scroll += DataGridView_Scroll;
            dataDisplayControl.DataGridViewCellClick += this.DataDisplayControl_DataGridViewCellClick;
            this.manageControl.ShowControl(dataDisplayControl);

            this.manageControl.NavMenuLeft.ItemHeight = 23;

            if(!string.IsNullOrEmpty(FolderPath) && (Directory.Exists(FolderPath) || File.Exists(FolderPath)))
            {
                BuildMenuForPath(FolderPath);
            }
            else
            {
                //左侧目录列表
                List<ManageMenu> manageMenus = new List<ManageMenu>();
                var drives = Directory.GetLogicalDrives();//获取盘符集合
                for(int i = 0 ; i < drives.Length ; i++)
                {
                    ManageMenu driveMenu = new ManageMenu
                    {
                        Id = i + 1,
                        NodeName = drives[i].Replace("\\",""),
                        NodeType = MenuNodeType.Folder,
                        NodePid = 0,
                        Remark = drives[i]
                    };
                    manageMenus.Add(driveMenu);
                }
                this.manageControl.SetMenuData(manageMenus,"目录列表");
            }

            this.txtFolderPath.Text = FolderPath;

            this.dataDisplayControl.BindContextMenuStrip(this.ContextMenuStripDgv);

            this.backgroundWorker_GetFileCount.RunWorkerAsync();//启动后台任务，用于统计目录大小和文件数量

            this.manageControl.BindContextMenuStripToFolder(this.ContextMenuStripNavMenu);

            this.manageControl.NavMenuLeft.ShowOneNode = true;
        }




        /// <summary>
        /// DataGridView单元格点击事件 实现：点击单元格联动左侧树菜单
        /// </summary>
        /// <param name="mouseButton"></param>
        /// <param name="column"></param>
        /// <param name="row"></param>
        /// <param name="cell"></param>
        private void DataDisplayControl_DataGridViewCellClick(DataGridViewEventArgs dataGridViewEventArgs)
        {
            string path = dataGridViewEventArgs.Row.Cells["Path"].Value.ToString();
            if(File.Exists(path))
            {
                path = Path.GetDirectoryName(path);
            }

            TreeNode parentNode = this.manageControl.NavMenuLeft.Nodes[0].Nodes.Cast<TreeNode>().FirstOrDefault(it =>
            {
                return it.Text == Path.GetPathRoot(path).Replace("\\","");
            });
            TreeNode node = TreeViewHelper.FindNode(parentNode,Path.GetFileName(path));

            if(node != null)
            {
                node.Parent.Expand();
                this.manageControl.NavMenuLeft.SelectedNode = node;
            }

        }

        #region 目录路径文本框

        private void txtFolderPath_ButtonClick(object sender,EventArgs e)
        {
            string dir = txtFolderPath.Text;
            if(Dialogs.SelectDir("请选择需要查看大小的目录",ref dir))
            {
                this.txtFolderPath.Text = dir;

                if(string.IsNullOrEmpty(this.txtFolderPath.Text)) return;

                BuildMenuForPath(this.txtFolderPath.Text);
            }
        }

        private void txtFolderPath_DoEnter(object sender,EventArgs e)
        {
            if(string.IsNullOrEmpty(this.txtFolderPath.Text)) return;

            BuildMenuForPath(this.txtFolderPath.Text);
        }

        #endregion 目录路径文本框


        #region 根据路径生成菜单

        /// <summary>
        /// 根据路径生成菜单
        /// </summary>
        /// <param name="folderPath"></param>
        private void BuildMenuForPath(string folderPath)
        {
            if(File.Exists(folderPath)) folderPath = Path.GetDirectoryName(folderPath);//如果是文件路径，那就转为目录路径

            this.manageControl.NavMenuLeft.ClearAll();

            List<ManageMenu> manageMenus = new List<ManageMenu>();

            var drives = Directory.GetLogicalDrives();//获取盘符集合
            for(int i = 0 ; i < drives.Length ; i++)
            {
                ManageMenu driveMenu = new ManageMenu
                {
                    Id = i + 1,
                    NodeName = drives[i].Replace("\\",""),
                    NodeType = MenuNodeType.Folder,
                    NodePid = 0,
                    Remark = drives[i]
                };
                manageMenus.Add(driveMenu);

                if(drives[i] == Path.GetPathRoot(folderPath))
                {
                    BuildMenuRecursive(folderPath,drives[i],driveMenu.Id,ref manageMenus);
                }

            }
            this.manageControl.SetMenuData(manageMenus,"目录列表");

            TreeNode parentNode = this.manageControl.NavMenuLeft.Nodes[0].Nodes.Cast<TreeNode>().FirstOrDefault(it =>
            {
                return it.Text == Path.GetPathRoot(folderPath).Replace("\\","");
            });

            ManageMenu targtMenu = manageMenus.FirstOrDefault(it =>
            {
                return it.Remark == folderPath.TrimEnd(Path.DirectorySeparatorChar);
            });

            var node = TreeViewHelper.FindNode(parentNode,targtMenu);

            if(node != null)
            {
                ShowForNode(node,targtMenu);
                node.Expand();
                this.manageControl.NavMenuLeft.SelectedNode = node;
            }
        }


        /// <summary>
        /// 递归生成菜单
        /// </summary>
        /// <param name="folderPath"></param>
        /// <param name="parentPath"></param>
        /// <param name="parentId"></param>
        /// <param name="manageMenus"></param>
        private void BuildMenuRecursive(string folderPath,string parentPath,int parentId,ref List<ManageMenu> manageMenus)
        {
            DirectoryInfo[] folders = new DirectoryInfo[] { };

            try
            {
                DirectoryInfo directoryInfo = new DirectoryInfo(parentPath);
                folders = directoryInfo.GetDirectories();
            }
            catch(Exception ex)
            {
            }

            foreach(var folder in folders)
            {
                int maxId = manageMenus.Max(x =>
                {
                    return x.Id;
                }) + 1;

                ManageMenu folderMenu = new ManageMenu
                {
                    Id = maxId++,
                    NodeName = folder.Name,
                    NodeType = MenuNodeType.Folder,
                    NodePid = parentId,
                    Remark = folder.FullName
                };
                manageMenus.Add(folderMenu);

                if(folderPath.Contains(folder.FullName))
                    BuildMenuRecursive(folderPath,folder.FullName,folderMenu.Id,ref manageMenus);
            }
        }

        #endregion 根据路径生成菜单


        /// <summary>
        /// 左侧树菜单单击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void manageControl_MenuClick(object sender,MenuEventArgs e)
        {
            var treeNodeMouseClickEventArgs = sender as TreeNodeMouseClickEventArgs;

            if(treeNodeMouseClickEventArgs.Button == MouseButtons.Right) return;

            ShowForNode(e.TreeNode,e.ManageMenu);
        }


        /// <summary>
        /// 根据点击的节点，显示右侧DataGridView数据
        /// </summary>
        /// <param name="node"></param>
        /// <param name="manageMenu"></param>
        /// <param name="refresh"></param>
        private void ShowForNode(TreeNode node,ManageMenu manageMenu,bool refresh = false)
        {
            if(!refresh && this.lastSelectedManageMenu != null && this.lastSelectedManageMenu.Remark == manageMenu.Remark) return;

            this.lastSelectedManageMenu = manageMenu;
            try
            {


                this.folderSize = 0;
                this.fileCount = 0;
                this.folderCount = 0;

                cts?.Cancel();// 取消之前的任务，不等待其完成

                // 初始化新的 CancellationTokenSource
                cts = new CancellationTokenSource();

                while(bags.TryTake(out _)) ;//清空后台任务队列

                resultTable?.Dispose();//释放DataTable，重新来过


                //初始化DataTable
                resultTable = new DataTable("ResultTable");
                resultTable.Columns.Add("Icon",typeof(Icon));
                resultTable.Columns.Add("Name",typeof(string));
                resultTable.Columns.Add("Size",typeof(long));
                resultTable.Columns.Add("SizeFormat",typeof(string));
                resultTable.Columns.Add("FileCount",typeof(int));
                resultTable.Columns.Add("FolderCount",typeof(int));
                resultTable.Columns.Add("Path",typeof(string));
                resultTable.Columns.Add("Type",typeof(MenuNodeType));

                this.dataDisplayControl.BindData(resultTable,this.dataGridColumns,"Size DESC");

                int maxId = TreeViewHelper.GetMaxImageIndex(this.manageControl.NavMenuLeft) + 1;

                List<ManageMenu> manageMenus = new List<ManageMenu>();

                DirectoryInfo directoryInfo = new DirectoryInfo(manageMenu.Remark);

                var folders = directoryInfo.GetDirectories();
                resultTable.BeginLoadData();
                foreach(var folder in folders)
                {
                    if(!refresh && node.Nodes.Count <= 0)
                    {
                        ManageMenu folderMenu = new ManageMenu
                        {
                            Id = maxId++,
                            NodeName = folder.Name,
                            NodeType = MenuNodeType.Folder,
                            NodePid = manageMenu.Id,
                            Remark = folder.FullName
                        };

                        manageMenus.Add(folderMenu);
                    }

                    DataRow dataRow = resultTable.NewRow();
                    dataRow["Name"] = folder.Name;
                    dataRow["Size"] = -1;
                    dataRow["SizeFormat"] = "";
                    dataRow["FileCount"] = -1;
                    dataRow["FolderCount"] = -1;
                    dataRow["Path"] = folder.FullName;
                    dataRow["Type"] = MenuNodeType.Folder;

                    resultTable.Rows.Add(dataRow);

                    this.bags.Add(folder.FullName);//添加到任务队列
                }

                if(manageMenus.Count > 0)
                    this.manageControl.BindMenuData(node,manageMenus);

                var files = directoryInfo.GetFiles();
                foreach(var file in files)
                {
                    DataRow dataRow = resultTable.NewRow();

                    dataRow["Name"] = file.Name;
                    dataRow["Size"] = file.Length;
                    dataRow["SizeFormat"] = StorageHelper.FormatBytes(file.Length);
                    dataRow["FileCount"] = 0;
                    dataRow["FolderCount"] = 0;
                    dataRow["Path"] = file.FullName;
                    dataRow["Type"] = MenuNodeType.Node;

                    resultTable.Rows.Add(dataRow);

                    this.bags.Add(file.FullName);//添加到任务队列
                }

                resultTable.EndLoadData();
                resultTable.AcceptChanges();

                SetIcon();
            }
            catch(Exception ex)
            {
                this.ShowWarningNotifier(ex.Message);
            }
        }

        #region 后台任务 获取文件数量、目录大小

        private void backgroundWorker_GetFileCount_DoWork(object sender,System.ComponentModel.DoWorkEventArgs e)
        {
            while(true)
            {
                if(this.backgroundWorker_GetFileCount.CancellationPending) break;

                if(bags.TryTake(out string path))
                {
                    try
                    {
                        if(File.Exists(path))//文件
                        {
                            backgroundWorker_GetFileCount.ReportProgress(0,new Tuple<string,int,int,long>(path,-1,-1,-1));//报告状态，展示结果
                        }
                        else//目录
                        {
                            Task<Tuple<string,int,int,long>>.Factory.StartNew(() =>
                            {
                                try
                                {
                                    DirectoryInfo directoryInfo = new DirectoryInfo(path);// 获取目录信息

                                    int folderCount = directoryInfo.GetDirectories("*",SearchOption.AllDirectories).Length;//文件夹数量


                                    cts.Token.ThrowIfCancellationRequested();// 检查取消标识

                                    var files = directoryInfo.GetFiles("*.*",SearchOption.AllDirectories);// 获取所有文件

                                    cts.Token.ThrowIfCancellationRequested();// 检查取消标识

                                    int fileCount = files.Length;// 文件数量                                        
                                    long size = files.Sum(it =>
                                    {
                                        return it.Length;
                                    });// 文件大小总和 

                                    return new Tuple<string,int,int,long>(path,folderCount,fileCount,size);
                                }
                                catch(OperationCanceledException)//任务被取消时触发该异常
                                {
                                    return null;
                                }
                                catch(Exception ex)
                                {
                                    return null;
                                }
                            },cts.Token).ContinueWith(t =>
                            {
                                backgroundWorker_GetFileCount.ReportProgress(0,t.Result);//报告状态，展示结果

                            },TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.PreferFairness);

                            Thread.Sleep(100);
                        }
                    }
                    catch(Exception ex)
                    {
                        Thread.Sleep(100);
                    }
                }
            }
        }


        private void backgroundWorker_GetFileCount_ProgressChanged(object sender,System.ComponentModel.ProgressChangedEventArgs e)
        {
            Tuple<string,int,int,long> tuple = e.UserState as Tuple<string,int,int,long>;

            if(tuple != null && this.resultTable != null)
            {
                foreach(DataRow dataRow in this.resultTable.Rows)
                {
                    if(dataRow["Path"].ToString() == tuple.Item1)
                    {
                        if(tuple.Item2 >= 0)
                            dataRow["FolderCount"] = tuple.Item2;

                        if(tuple.Item3 >= 0)
                            dataRow["FileCount"] = tuple.Item3;

                        if(tuple.Item4 >= 0)
                        {
                            dataRow["Size"] = tuple.Item4;
                            dataRow["SizeFormat"] = StorageHelper.FormatBytes(tuple.Item4);

                            this.dataDisplayControl.DataGridView.Invalidate();// 标记控件为需要重绘  
                            this.dataDisplayControl.DataGridView.Update();// 立即重绘控件
                        }

                        //占用空间
                        this.folderSize += Convert.ToInt64(dataRow["Size"]);
                        break;
                    }
                }

                if(tuple.Item1.Contains(this.manageControl.SelectedManageMenu.Remark))
                {
                    //文件/目录数量
                    if(File.Exists(tuple.Item1))//文件
                    {
                        this.fileCount += 1;
                    }
                    else//目录
                    {
                        this.folderCount += 1;
                        this.folderCount += tuple.Item2;

                        this.fileCount += tuple.Item3;
                    }
                    dataDisplayControl.TitleText = $"占用空间：{StorageHelper.FormatBytes(this.folderSize)}  文件数量：{this.fileCount}  目录数量：{this.folderCount}";
                }
            }
        }


        #endregion 后台任务 获取文件数量、目录大小


        #region 延迟设置DataGridView的图标

        /// <summary>
        /// DataGridView滚动条事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DataGridView_Scroll(object sender,ScrollEventArgs e)
        {
            SetIcon();
        }

        /// <summary>
        /// 设置图标
        /// </summary>
        private void SetIcon()
        {
            List<int> visibleRows = GetVisibleRows();

            if(visibleRows == null || visibleRows.Count <= 0)
            {
                if(dataDisplayControl.DataGridView.Rows.Count > 0)
                {
                    int rowCount = dataDisplayControl.DataGridView.Rows.Count > 40 ? 40 : dataDisplayControl.DataGridView.Rows.Count;
                    visibleRows = Enumerable.Range(0,rowCount).ToList();
                }
            }

            foreach(int rowIndex in visibleRows)
            {
                try
                {
                    var value = dataDisplayControl.DataGridView.Rows[rowIndex].Cells["Icon"].Value;

                    if(value != null && !string.IsNullOrEmpty(value.ToString())) continue;

                    string path = dataDisplayControl.DataGridView.Rows[rowIndex].Cells["Path"].Value.ToString();

                    MenuNodeType nodeType = (MenuNodeType)dataDisplayControl.DataGridView.Rows[rowIndex].Cells["Type"].Value;

                    string extension = Path.GetExtension(path);
                    if(nodeType == MenuNodeType.Folder) extension = "dir";

                    if(!IconCache.TryGetValue(extension,out Icon icon))
                    {
                        icon = IconHelper.GetFileIcon(path);
                        IconCache.Add(extension,icon);
                    }

                    dataDisplayControl.DataGridView.Rows[rowIndex].Cells["Icon"].Value = icon;
                }
                catch
                {

                }
            }
        }

        /// <summary>
        /// 获取当前可视区域的行索引集合
        /// </summary>
        /// <returns>可见行的集合</returns>
        private List<int> GetVisibleRows()
        {
            List<int> visibleRows = new List<int>();

            if(dataDisplayControl.DataGridView == null || dataDisplayControl.DataGridView.RowCount == 0)
            {
                // 返回空列表，如果没有数据或DataGridView为空
                return visibleRows;
            }

            // 获取第一个可见行的索引
            int firstVisibleRow = dataDisplayControl.DataGridView.FirstDisplayedScrollingRowIndex;

            if(firstVisibleRow == -1)
            {
                // 没有可见的行，返回空列表
                return visibleRows;
            }

            // 获取可见的行数
            int displayedRowCount = dataDisplayControl.DataGridView.DisplayedRowCount(true);

            for(int i = 0 ; i < displayedRowCount ; i++)
            {
                int rowIndex = firstVisibleRow + i;

                // 确保索引在有效范围内
                if(rowIndex < dataDisplayControl.DataGridView.RowCount)
                {
                    visibleRows.Add(rowIndex);
                }
            }

            return visibleRows;
        }

        #endregion 延迟设置DataGridView的图标


        #region DataGridView右键菜单

        private void 打开路径ToolStripMenuItem_Click(object sender,EventArgs e)
        {
            try
            {
                string path = this.dataDisplayControl.SelectedRowDic["Path"];

                Dialogs.OpenDir(path);

            }
            catch(Exception ex)
            {
                this.ShowErrorDialog("打开路径失败：" + ex.ToString());
            }
        }

        private void 复制路径ToolStripMenuItem_Click(object sender,EventArgs e)
        {
            try
            {
                string path = this.dataDisplayControl.SelectedRowDic["Path"];

                Clipboard.SetText(path);
                this.ShowSuccessTip("复制成功");
            }
            catch(Exception ex)
            {
                this.ShowErrorDialog("复制路径失败：" + ex.ToString());
            }
        }

        private void 属性ToolStripMenuItem_Click(object sender,EventArgs e)
        {
            try
            {
                string path = this.dataDisplayControl.SelectedRowDic["Path"];

                FileHelper.ShowFileProperties(path);
            }
            catch(Exception ex)
            {
                this.ShowErrorDialog("打开属性失败：" + ex.ToString());
            }
        }

        private void 打开文件ToolStripMenuItem_Click(object sender,EventArgs e)
        {
            try
            {
                string path = this.dataDisplayControl.SelectedRowDic["Path"];

                if(File.Exists(path))
                {
                    Process.Start(path);
                }
                else
                {
                    Dialogs.OpenDir(path);
                }
            }
            catch(Exception ex)
            {
                this.ShowErrorDialog("打开路径失败：" + ex.ToString());
            }
        }

        #endregion DataGridView右键菜单


        #region 左侧树菜单 右键菜单

        private void 打开路径ToolStripMenuItem1_Click(object sender,EventArgs e)
        {
            try
            {
                Dialogs.OpenDir(this.manageControl.SelectedManageMenu.Remark);
            }
            catch(Exception ex)
            {
                this.ShowErrorDialog("打开路径失败：" + ex.ToString());
            }
        }

        private void 复制路径ToolStripMenuItem1_Click(object sender,EventArgs e)
        {
            try
            {
                Clipboard.SetText(this.manageControl.SelectedManageMenu.Remark);
                this.ShowSuccessTip("复制成功");
            }
            catch(Exception ex)
            {
                this.ShowErrorDialog("复制路径失败：" + ex.ToString());
            }
        }


        private void 目录属性ToolStripMenuItem1_Click(object sender,EventArgs e)
        {
            try
            {
                FileHelper.ShowFileProperties(this.manageControl.SelectedManageMenu.Remark);
            }
            catch(Exception ex)
            {
                this.ShowErrorDialog("打开属性失败：" + ex.ToString());
            }
        }

        private void 刷新ToolStripMenuItem_Click(object sender,EventArgs e)
        {
            this.ShowForNode(this.manageControl.SelectedTreeNode,this.manageControl.SelectedManageMenu,true);
        }

        #endregion 左侧树菜单 右键菜单


        private void FolderSizeForm_Disposed(object sender,EventArgs e)
        {
            try
            {
                cts?.Cancel();

                this.backgroundWorker_GetFileCount.CancelAsync();
            }
            catch(Exception ex)
            {
            }
        }

        private void manageControl_MenuDrag(object sender,MenuEventArgs e)
        {
            e.Cancel = true;
        }
    }
}
